package per.poker.gonghua;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.scene.paint.Color;
import javafx.stage.StageStyle;
import javafx.util.Pair;
import lombok.extern.slf4j.Slf4j;
import per.poker.common.CommonService;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
import java.util.stream.Collectors;

@Slf4j
public class GonghuaService extends GonghuaData {

    private Game game;
    private Thread thread = null;
    private int waitTime = 100;
    private final List<String> useCards = new LinkedList<>();

    public void startGame() throws InterruptedException {

        discard.setDisable(true);
        pass.setDisable(true);
        surrender.setDisable(true);
        thread = Thread.currentThread();

        //int start = 3;
        int start = RandomUtil.randomInt(0, 4);
        log.info("轮到:{}", start);
        Player startPlayer = game.getPlayerList().get(start);
        startPlayer.setRole(RoleEnum.ATK);
        AtomicInteger idx = new AtomicInteger(start);

        showTip(StrUtil.format("————————本局主花色为：{}————————",
                EnumUtil.getBy(TypeEnum.class, e -> ObjectUtil.equal(e.getCode(), game.getMainColor())).getName()));

        while (game.getIsStarted()) {

            startPlayer = game.getPlayerList().get(idx.get() % 4);
            RoleEnum tmpRole = startPlayer.getRole();
            if (startPlayer.getFinished() && tmpRole == null) {

                do {
                    startPlayer = game.getPlayerList().get(idx.incrementAndGet() % 4);
                } while (startPlayer.getFinished());

                startPlayer.setRole(RoleEnum.ATK);
            }

            Thread.sleep(waitTime);
            print();

            //找到下家
            Player p;
            do {
                List<Player> playerList = game.getPlayerList();
                int index = (idx.get() + 1) % 4;
                p = playerList.get(index);
                idx.incrementAndGet();
            } while (p.getFinished());

            //轮到玩家
            if ("south".equals(startPlayer.getName())) {

                //玩家是主攻方
                if (startPlayer.getRole() == RoleEnum.ATK) {
                    //下家受攻
                    p.setRole(RoleEnum.DEF);
                    Player finalStartPlayer1 = startPlayer;
                    Player finalP1 = p;
                    //设置其他玩家为助攻方
                    game.getPlayerList().stream()
                            .filter(a -> !a.getFinished())
                            .filter(a -> ObjectUtil.notEqual(a.getName(), finalStartPlayer1.getName()))
                            .filter(a -> ObjectUtil.notEqual(a.getName(), finalP1.getName()))
                            .forEach(a -> a.setRole(RoleEnum.ASI));

                    showTip(StrUtil.format("————————轮到玩家 {}  主攻————————", startPlayer.getName()));

                    discard.setDisable(false);
                    surrender.setDisable(true);
                    pass.setDisable(true);
                    //已经出过牌才允许跳过
                    if (!game.getBattleMap().isEmpty()) {
                        pass.setDisable(false);
                    }
                    LockSupport.park();

                }
                //玩家是受攻方
                else if (startPlayer.getRole() == RoleEnum.DEF) {

                    showTip(StrUtil.format("————————轮到玩家 {}  受攻————————", startPlayer.getName()));

                    //不满6张，先补牌
                    fillCard(startPlayer);

                    boolean allDef = game.getBattleMap().entrySet().stream().allMatch(c -> c.getValue() != null);

                    Player finalStartPlayer2 = startPlayer;
                    boolean allPass = game.getPlayerList().stream()
                            .filter(c -> !c.getFinished())
                            .filter(c -> ObjectUtil.notEqual(c.getName(), finalStartPlayer2.getName())).allMatch(Player::getHasPassed);
                    //所有牌都防住，所有玩家都跳过
                    if (allDef && allPass) {

                        showTip(StrUtil.format("————————玩家 {} 完全防守成功————————", startPlayer.getName()));
                        game.getBattleMap().clear();

                        startPlayer.setRole(RoleEnum.ATK);
                        idx.set(startPlayer.getTurn());

                        for (Player player : game.getPlayerList()) {
                            try {
                                fillCard(player);
                            } catch (InterruptedException ex) {
                                throw new RuntimeException(ex);
                            }
                        }
                        end();
                    }
                    //仍有主攻方或助攻方
                    else {
                        discard.setDisable(false);
                        surrender.setDisable(false);
                        pass.setDisable(true);
                        LockSupport.park();
                        //玩家防守失败收回了所有的牌
                        if (game.getBattleMap().isEmpty() && game.getLastAtkIdx() != 1) {
                            idx.set(game.getLastAtkIdx() % 4);
                        }
                        //玩家已经出完所有牌了
                        if (startPlayer.getCards().isEmpty()) {
                            p.setRole(RoleEnum.ATK);
                            game.setLastAtkIdx(null);
                        }
                        end();
                    }

                }
                //玩家是助攻方
                else {
                    showTip(StrUtil.format("————————轮到玩家 {}  助攻————————", startPlayer.getName()));

                    discard.setDisable(false);
                    surrender.setDisable(true);
                    pass.setDisable(false);

                    LockSupport.park();
                }

            }
            //轮到电脑
            else {

                //电脑是主攻方
                if (startPlayer.getRole() == RoleEnum.ATK) {
                    //下家受攻
                    p.setRole(RoleEnum.DEF);

                    Player finalStartPlayer1 = startPlayer;
                    Player finalP1 = p;
                    //设置其他玩家为助攻方
                    game.getPlayerList().stream()
                            .filter(a -> !a.getFinished())
                            .filter(a -> ObjectUtil.notEqual(a.getName(), finalStartPlayer1.getName()))
                            .filter(a -> ObjectUtil.notEqual(a.getName(), finalP1.getName()))
                            .forEach(a -> a.setRole(RoleEnum.ASI));

                    showTip(StrUtil.format("————————轮到玩家 {}  主攻————————", startPlayer.getName()));

                    //首先出牌只能出一张，或者相同点数的牌
                    if (game.getBattleMap().isEmpty()) {

                        showTip("—————————————————————————————————————————");

                        //找出最小的牌
                        String num = startPlayer.getCards().stream().sorted((o1, o2) -> {
                            CardEnum c1 = EnumUtil.getBy(CardEnum.class, c -> ObjectUtil.equals(c.getCode(), o1.substring(1)));
                            CardEnum c2 = EnumUtil.getBy(CardEnum.class, c -> ObjectUtil.equals(c.getCode(), o2.substring(1)));
                            if (c1 == null) {
                                return 1;
                            }
                            if (c2 == null) {
                                return -1;
                            }
                            return Integer.compare(c1.getNum(), c2.getNum());
                        }).collect(Collectors.toList()).get(0).substring(1);

                        List<Node> selectedNodes = startPlayer.getPane().getChildren().stream()
                                .filter(n -> ObjectUtil.equal(n.getId().substring(1), num))
                                .collect(Collectors.toList());

                        discardTip(StrUtil.format("——————主攻  {} 出牌——————", startPlayer.getName()),
                                selectedNodes, startPlayer);

                        game.setLastAtkIdx(startPlayer.getTurn());

                    }
                    //再次进攻或者防守可以出不同的牌，但出牌的点数只能跟出过的牌相同
                    else {

                        Set<String> allCards = new HashSet<>();
                        List<Node> selectedNodes = new LinkedList<>();
                        game.getBattleMap().forEach((k, v) -> {
                            allCards.add(k);
                            if (v != null) {
                                allCards.add(v);
                            }
                        });
                        //限制场上的攻牌最多6张
                        long toDefCardNum = 6 - game.getBattleMap().entrySet().stream()
                                .filter(e -> e.getValue() == null).count();
                        AtomicInteger existsCardNum = new AtomicInteger(0);

                        for (Node node : startPlayer.getPane().getChildren()) {
                            if (allCards.contains("大王") || allCards.contains("小王")) {
                                break;
                            }
                            if (allCards.stream().map(c -> c.substring(1)).collect(Collectors.toList())
                                    .contains(node.getId().substring(1))) {
                                if (existsCardNum.get() == toDefCardNum) {
                                    break;
                                }
                                selectedNodes.add(node);
                                existsCardNum.incrementAndGet();
                            }
                        }

                        //没有能出的牌，跳过
                        if (selectedNodes.isEmpty()) {
                            pass(startPlayer);
                        }
                        //可以出牌
                        else {

                            discardTip(StrUtil.format("——————主攻  {} 出牌——————", startPlayer.getName()),
                                    selectedNodes, startPlayer);

                            game.setLastAtkIdx(startPlayer.getTurn());

                        }

                    }

                }
                //电脑受攻方
                else if (startPlayer.getRole() == RoleEnum.DEF) {

                    Player finalStartPlayer = startPlayer;

                    showTip(StrUtil.format("————————轮到玩家 {}  受攻————————", startPlayer.getName()));

                    //不满6张，先补牌
                    fillCard(startPlayer);

                    boolean allDef = game.getBattleMap().entrySet().stream().allMatch(c -> c.getValue() != null);

                    boolean allPass = game.getPlayerList().stream()
                            .filter(c -> !c.getFinished())
                            .filter(c -> ObjectUtil.notEqual(c.getName(), finalStartPlayer.getName())).allMatch(Player::getHasPassed);
                    if (allDef && allPass) {

                        showTip(StrUtil.format("————————玩家 {} 完全防守成功————————", startPlayer.getName()));
                        game.getBattleMap().clear();

                        startPlayer.setRole(RoleEnum.ATK);
                        idx.set(startPlayer.getTurn());

                        for (Player player : game.getPlayerList()) {
                            try {
                                fillCard(player);
                            } catch (InterruptedException ex) {
                                throw new RuntimeException(ex);
                            }
                        }
                        end();
                    }
                    //仍有主攻方或助攻方
                    else {

                        //将进攻方的牌按从小到大排序
                        List<String> atkCards = game.getBattleMap().entrySet().stream()
                                .filter(c -> c.getValue() == null).map(Map.Entry::getKey).collect(Collectors.toList());
                        PokerGen.sortCard(atkCards, game.getMainColor());

                        List<String> usedCards = new LinkedList<>();
                        for (String toDefCard : atkCards) {
                            for (String card : startPlayer.getCards()) {
                                if (PokerGen.compareCard(card, toDefCard, game.getMainColor()) == 1 && !usedCards.contains(card)) {
                                    game.getBattleMap().put(toDefCard, card);
                                    usedCards.add(card);
                                    break;
                                }
                            }
                        }
                        startPlayer.getCards().removeAll(usedCards);
                        if (game.getRestCards().isEmpty() && startPlayer.getCards().isEmpty()) {
                            log.info("玩家 {} 出完所有的牌", startPlayer.getName());
                        }

                        List<Node> selectedNodes = startPlayer.getPane().getChildren().stream()
                                .filter(c -> usedCards.contains(c.getId())).collect(Collectors.toList());

                        //防守失败
                        if (!startPlayer.getCards().isEmpty() && atkCards.size() > usedCards.size()) {
                            showTip(StrUtil.format("玩家 {} 防守失败，收回所有的牌", startPlayer.getName()));

                            Set<String> backCards = new HashSet<>(startPlayer.getCards());
                            game.getBattleMap().forEach((k, v) -> {
                                backCards.add(k);
                                if (v != null) {
                                    backCards.add(v);
                                }
                            });

                            startPlayer.getCards().clear();
                            startPlayer.getCards().addAll(backCards);
                            startPlayer.getCards().sort((o1, o2) -> PokerGen.compareCard(o1, o2, game.getMainColor()));

                            CommonService.runLater(() -> {
                                finalStartPlayer.getPane().getChildren().clear();

                                for (String playerCard : finalStartPlayer.getCards()) {
                                    setCardFlow(finalStartPlayer.getName(), playerCard);
                                }
                            });

                            idx.set(game.getLastAtkIdx() % 4);
                            //由进攻成功的主攻或者助攻继续作为主攻方
                            game.getPlayerList().get(game.getLastAtkIdx() % 4).setRole(RoleEnum.ATK);

                            game.getBattleMap().clear();
                            for (Player player : game.getPlayerList()) {
                                try {
                                    fillCard(player);
                                } catch (InterruptedException ex) {
                                    throw new RuntimeException(ex);
                                }
                            }
                            end();
                        }
                        //防守成功
                        else if (atkCards.size() == usedCards.size()) {
                            showTip(StrUtil.format("玩家 {} 成功防守", startPlayer.getName()));

                            discardTip(StrUtil.format("——————受攻  {} 出牌——————", startPlayer.getName()),
                                    selectedNodes, startPlayer);

                            //玩家已经出完所有牌了
                            if (game.getRestCards().isEmpty() && startPlayer.getCards().isEmpty()) {
                                p.setRole(RoleEnum.ATK);
                                game.setLastAtkIdx(null);
                                log.info("——————受攻  {} 出完所有的牌——————", startPlayer.getName());
                                startPlayer.setFinished(true);
                                startPlayer.setRole(null);
                                game.getBattleMap().clear();
                            }
                            end();

                        }
                        //出完所有牌
                        else if (startPlayer.getCards().isEmpty() && atkCards.size() > usedCards.size()) {
                            log.info("玩家 {} 出完所有的牌", startPlayer.getName());

                            discardTip(StrUtil.format("——————受攻  {} 出完所有的牌——————", startPlayer.getName()),
                                    selectedNodes, startPlayer);

                            startPlayer.setFinished(true);
                            startPlayer.setRole(null);
                            game.getBattleMap().clear();
                            log.info("——————受攻  {} 出完所有的牌——————", startPlayer.getName());
                            p.setRole(RoleEnum.ATK);
                            game.setLastAtkIdx(null);
                            end();
                        } else {
                            throw new RuntimeException("error");
                        }

                    }


                }
                //电脑是助攻方
                else {

                    showTip(StrUtil.format("————————轮到玩家 {}  助攻————————", startPlayer.getName()));

                    Set<String> allCards = new HashSet<>();
                    List<Node> selectedNodes = new LinkedList<>();
                    game.getBattleMap().forEach((k, v) -> {
                        allCards.add(k);
                        if (v != null) {
                            allCards.add(v);
                        }
                    });
                    //限制场上的攻牌最多6张
                    long toDefCardNum = 6 - game.getBattleMap().entrySet().stream()
                            .filter(e -> e.getValue() == null).count();
                    AtomicInteger existsCardNum = new AtomicInteger(0);

                    for (Node node : startPlayer.getPane().getChildren()) {
                        if (allCards.contains("大王") || allCards.contains("小王")) {
                            break;
                        }
                        if (allCards.stream().map(c -> c.substring(1)).collect(Collectors.toList())
                                .contains(node.getId().substring(1))) {
                            if (existsCardNum.get() == toDefCardNum) {
                                break;
                            }
                            selectedNodes.add(node);
                            existsCardNum.incrementAndGet();
                        }
                    }

                    //没有能出的牌，跳过
                    if (selectedNodes.isEmpty()) {
                        pass(startPlayer);
                    }
                    //可以出牌
                    else {

                        discardTip(StrUtil.format("——————助攻  {} 出牌——————", startPlayer.getName()),
                                selectedNodes, startPlayer);

                        game.setLastAtkIdx(startPlayer.getTurn());

                    }

                }
            }

        }
    }

    private void showTip(String text) throws InterruptedException {
        log.info(text);
        Label label = new Label();
        label.setPrefWidth(660);
        label.setPrefHeight(36);
        label.setText(text);
        label.setAlignment(Pos.CENTER);

        if (Thread.currentThread().getId() == thread.getId()) {
            CommonService.runLater(() -> {
                stage.getChildren().add(label);
                scrollPane.vvalueProperty().setValue(1.0);
            });
        } else {
            stage.getChildren().add(label);
            scrollPane.vvalueProperty().setValue(1.0);
        }

    }

    private void discardTip(String text, List<Node> selectedNodes, Player startPlayer) throws InterruptedException {

        Label mainAtk = new Label();
        mainAtk.setAlignment(Pos.CENTER);
        mainAtk.setPrefWidth(660);
        mainAtk.setPrefHeight(36);
        mainAtk.setText(text);

        FlowPane displayStage = new FlowPane();
        displayStage.setPrefWidth(660);
        displayStage.setPrefHeight(115);

        List<String> cards = selectedNodes.stream().map(Node::getId).collect(Collectors.toList());
        log.info(text + "{}", cards);

        for (Node node : selectedNodes) {
            ImageView imageView = new ImageView();
            imageView.setId(node.getId());
            imageView.setFitWidth(53);
            imageView.setFitHeight(75);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/" + node.getId() + ".jpg")));
            displayStage.getChildren().add(imageView);

            if (startPlayer.getRole() != RoleEnum.DEF) {
                game.getBattleMap().put(node.getId(), null);
            }

        }

        Runnable r = () -> {
            startPlayer.getPane().getChildren().removeAll(selectedNodes);
            stage.getChildren().add(mainAtk);
            stage.getChildren().add(displayStage);
        };

        if (ObjectUtil.equal(startPlayer.getName(), "south")) {
            Platform.runLater(r);
        } else {
            CommonService.runLater(r);
        }

        startPlayer.getCards().removeAll(cards);
        if (game.getRestCards().isEmpty() && startPlayer.getCards().isEmpty()) {
            startPlayer.setFinished(true);
            startPlayer.setRole(null);
        }
    }

    private void fillCard(Player startPlayer) throws InterruptedException {
        //小于6张牌，先补牌
        if (startPlayer.getCards().size() < 6 && !game.getRestCards().isEmpty()) {

            log.info("剩余牌堆:{}", game.getRestCards());

            showTip(StrUtil.format("玩家 {} 补牌", startPlayer.getName()));

            //要补的牌比牌堆还多的情况
            int size = 6 - startPlayer.getCards().size();
            if (size < game.getRestCards().size()) {

                startPlayer.getCards().addAll(game.getRestCards().subList(0, size));

                PokerGen.sortCard(startPlayer.getCards(), game.getMainColor());

                CommonService.runLater(() -> {
                    startPlayer.getPane().getChildren().clear();

                    for (String playerCard : startPlayer.getCards()) {
                        setCardFlow(startPlayer.getName(), playerCard);
                    }
                });

                game.setRestCards(game.getRestCards().subList(size, game.getRestCards().size()));

            }
            //剩余牌堆不够6张，全部补完
            else {

                startPlayer.getCards().addAll(game.getRestCards());
                CommonService.runLater(() -> {
                    startPlayer.getPane().getChildren().clear();

                    for (String playerCard : startPlayer.getCards()) {
                        setCardFlow(startPlayer.getName(), playerCard);
                    }
                });

                game.getRestCards().clear();

            }
        }
    }

    private void fillUserCard(Player startPlayer) throws InterruptedException {
        //小于6张牌，先补牌
        if (startPlayer.getCards().size() < 6 && !game.getRestCards().isEmpty()) {

            log.info("剩余牌堆:{}", game.getRestCards());

            log.info(StrUtil.format("玩家 {} 补牌", startPlayer.getName()));
            Label label = new Label();
            label.setPrefWidth(660);
            label.setPrefHeight(36);
            label.setText(StrUtil.format("玩家 {} 补牌", startPlayer.getName()));
            label.setAlignment(Pos.CENTER);
            stage.getChildren().add(label);
            scrollPane.vvalueProperty().setValue(1.0);
            if (game.getRestCards().size() > 6) {
                int size = 6 - startPlayer.getCards().size();
                startPlayer.getCards().addAll(game.getRestCards().subList(0, size));
                startPlayer.getPane().getChildren().clear();

                for (String playerCard : startPlayer.getCards()) {
                    setCardFlow(startPlayer.getName(), playerCard);
                }

                game.setRestCards(game.getRestCards().subList(size, game.getRestCards().size()));

            }
            //剩余牌堆不够6张，全部补完
            else {

                startPlayer.getCards().addAll(game.getRestCards());
                startPlayer.getPane().getChildren().clear();

                for (String playerCard : startPlayer.getCards()) {
                    setCardFlow(startPlayer.getName(), playerCard);
                }
                game.getRestCards().clear();

            }
        }
    }

    public void initButton() {

        discard.setOnMouseClicked(e -> {

            List<Node> selectedNodes = south.getChildren().stream()
                    .filter(c -> c.getEffect() != null)
                    .collect(Collectors.toList());
            if (selectedNodes.isEmpty()) {
                CommonService.errorDialog("未选择牌");
                return;
            }

            //首先出牌只能出一张，或者相同点数的牌
            if (game.getBattleMap().isEmpty()) {

                boolean allSame = selectedNodes.stream().allMatch(c ->
                        ObjectUtil.equal(c.getId().substring(1), selectedNodes.get(0).getId().substring(1)));
                if (!allSame) {
                    CommonService.errorDialog("只能选择相同点数的牌");
                    return;
                }

                try {
                    showTip("—————————————————————————————————————————");
                    discardTip("——————主攻  south 出牌——————", selectedNodes, game.getPlayerList().get(1));
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }

                game.setLastAtkIdx(1);
            }
            //再次进攻或者防守可以出不同的牌，但出牌的点数只能跟出过的牌相同
            else {

                Set<String> allCards = new HashSet<>();
                Set<String> toDefCards = new HashSet<>();
                game.getBattleMap().forEach((k, v) -> {
                    allCards.add(k);
                    if (v != null) {
                        allCards.add(v);
                    } else {
                        toDefCards.add(k);
                    }
                });
                //限制场上的攻牌最多6张
                long toDefCardNum = game.getBattleMap().entrySet().stream().filter(k -> k.getValue() == null).count();

                //主攻
                if (game.getPlayerList().get(1).getRole() == RoleEnum.ATK) {

                    if (allCards.contains("大王") || allCards.contains("小王")) {
                        CommonService.errorDialog("存在封牌，不能跟牌了");
                        return;
                    }
                    if (selectedNodes.size() + toDefCardNum > 6) {
                        CommonService.errorDialog("攻牌数量不能超过6张");
                        return;
                    }
                    for (Node node : selectedNodes) {
                        if (!allCards.stream().map(c -> c.substring(1)).collect(Collectors.toList())
                                .contains(node.getId().substring(1))) {
                            CommonService.errorDialog("不能出场上没有的牌");
                            return;
                        }
                    }

                    try {
                        discardTip("——————主攻  south 出牌——————", selectedNodes, game.getPlayerList().get(1));
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }

                    game.setLastAtkIdx(1);
                }
                //助攻
                else if (game.getPlayerList().get(1).getRole() == RoleEnum.ASI) {

                    if (allCards.contains("大王") || allCards.contains("小王")) {
                        CommonService.errorDialog("存在封牌，不能跟牌了");
                        return;
                    }
                    if (selectedNodes.size() + toDefCardNum > 6) {
                        CommonService.errorDialog("攻牌数量不能超过6张");
                        return;
                    }
                    for (Node node : selectedNodes) {
                        if (!allCards.stream().map(c -> c.substring(1)).collect(Collectors.toList())
                                .contains(node.getId().substring(1))) {
                            CommonService.errorDialog("不能出场上没有的牌");
                            return;
                        }
                    }

                    try {
                        discardTip("——————助攻  south 出牌——————", selectedNodes, game.getPlayerList().get(1));
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }

                    game.setLastAtkIdx(1);
                }
                //受攻
                else {

                    if (selectedNodes.size() > toDefCards.size()) {
                        CommonService.errorDialog("出牌过多");
                        return;
                    }
                    if (!game.getRestCards().isEmpty() && selectedNodes.size() < toDefCards.size()) {
                        CommonService.errorDialog("出牌过少");
                        return;
                    }

                    //到这里可能会出现攻方出的牌多于玩家手上的牌，且无牌可抽
//                    List<String> userSelectedCards = selectedNodes.stream().map(Node::getId).collect(Collectors.toList());
//                    PokerGen.sortCard(userSelectedCards, game.getMainColor());

                    List<String> toDef = game.getBattleMap().entrySet().stream()
                            .filter(kv -> kv.getValue() == null).map(Map.Entry::getKey)
                            .collect(Collectors.toList());

                    for (int i = 0; i < useCards.size(); i++) {
                        if (PokerGen.compareCard(toDef.get(i), useCards.get(i), game.getMainColor()) > -1) {
                            CommonService.errorDialog("出的牌太小");
                            for (Node child : game.getPlayerList().get(1).getPane().getChildren()) {
                                child.setEffect(null);
                            }
                            useCards.clear();
                            return;
                        }
                    }

                    for (int i = 0; i < useCards.size(); i++) {
                        game.getBattleMap().put(toDef.get(i), useCards.get(i));
                    }


                    try {
                        discardTip("——————受攻  south 出牌——————", selectedNodes, game.getPlayerList().get(1));
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }

                    //玩家出完所有的牌了,轮到下家作为主攻方
                    if (game.getPlayerList().get(1).getCards().isEmpty()) {
                        game.getPlayerList().get(1).setFinished(true);
                        game.getPlayerList().get(1).setRole(null);
                        game.getBattleMap().clear();
                        log.info("——————受攻  south 出完所有的牌——————");
                    }

                }
            }
            useCards.clear();
            LockSupport.unpark(thread);
        });

        pass.setOnMouseClicked(e -> {
            try {
                pass(game.getPlayerList().get(1));
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            LockSupport.unpark(thread);
        });

        surrender.setOnMouseClicked(e -> {

            log.info("玩家 south 防守失败，收回所有的牌");
            Label label = new Label();
            label.setPrefWidth(660);
            label.setPrefHeight(36);
            label.setText("玩家 south 防守失败，收回所有的牌");
            label.setAlignment(Pos.CENTER);
            stage.getChildren().add(label);
            scrollPane.vvalueProperty().setValue(1.0);

            Set<String> backCards = new HashSet<>(game.getPlayerList().get(1).getCards());
            game.getBattleMap().forEach((k, v) -> {
                backCards.add(k);
                if (v != null) {
                    backCards.add(v);
                }
            });

            game.getPlayerList().get(1).getCards().clear();
            game.getPlayerList().get(1).getCards().addAll(backCards);
            game.getPlayerList().get(1).getCards().sort((o1, o2) -> PokerGen.compareCard(o1, o2, game.getMainColor()));
            //game.getPlayerList().get(1).setCards(PokerGen.sortCard(game.getPlayerList().get(1).getCards(), game.getMainColor()));

            game.getPlayerList().get(1).getPane().getChildren().clear();

            game.getBattleMap().clear();

            for (String playerCard : game.getPlayerList().get(1).getCards()) {
                setCardFlow(game.getPlayerList().get(1).getName(), playerCard);
            }

            //由进攻成功的主攻或者助攻继续作为主攻方
            game.getPlayerList().get(game.getLastAtkIdx() % 4).setRole(RoleEnum.ATK);

            for (Player player : game.getPlayerList()) {
                try {
                    fillUserCard(player);
                } catch (InterruptedException ex) {
                    throw new RuntimeException(ex);
                }
            }
            LockSupport.unpark(thread);
        });
    }

    private void pass(Player player) throws InterruptedException {
        log.info("玩家 {} 跳过", player.getName());
        Label label = new Label();
        label.setPrefWidth(660);
        label.setPrefHeight(36);
        label.setText(StrUtil.format("玩家 {} 跳过", player.getName()));
        label.setAlignment(Pos.CENTER);
        Runnable r = () -> {
            stage.getChildren().add(label);
            scrollPane.vvalueProperty().setValue(1.0);
        };
        if (ObjectUtil.equal(player.getName(), "south")) {
            Platform.runLater(r);
        } else {
            CommonService.runLater(r);
        }

        player.setHasPassed(true);
    }

    public void showCard(Map<String, List<String>> cards) {

        south.getChildren().clear();
        north.getChildren().clear();
        east.getChildren().clear();
        west.getChildren().clear();

        for (String s : cards.get("south")) {
            ImageView imageView = new ImageView();
            imageView.setId(s);
            imageView.setFitWidth(53);
            imageView.setFitHeight(75);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/" + s + ".jpg")));
            south.getChildren().add(imageView);

            imageView.setOnMouseClicked(e -> {

                if (imageView.getEffect() == null) {
                    imageView.setEffect(new DropShadow(15, Color.RED));
                    useCards.add(s);
                } else {
                    useCards.remove(s);
                    imageView.setEffect(null);
                }

            });
        }

        for (String s : cards.get("north")) {
            ImageView imageView = new ImageView();
            imageView.setId(s);
            imageView.setFitWidth(53);
            imageView.setFitHeight(75);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/vertical.jpg")));
            north.getChildren().add(imageView);
        }

        for (String s : cards.get("east")) {
            ImageView imageView = new ImageView();
            imageView.setId(s);
            imageView.setFitWidth(75);
            imageView.setFitHeight(53);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/horizontal.jpg")));
            east.getChildren().add(imageView);
        }

        for (String s : cards.get("west")) {
            ImageView imageView = new ImageView();
            imageView.setId(s);
            imageView.setFitWidth(75);
            imageView.setFitHeight(53);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/horizontal.jpg")));
            west.getChildren().add(imageView);
        }

        List<Player> playerList = new ArrayList<>(8);

        playerList.add(new Player("east", cards.get("east"), false, false, null, east, 0));
        playerList.add(new Player("south", cards.get("south"), false, false, null, south, 1));
        playerList.add(new Player("west", cards.get("west"), false, false, null, west, 2));
        playerList.add(new Player("north", cards.get("north"), false, false, null, north, 3));

        game = new Game(playerList, Boolean.TRUE, cards.get("rest"),
                CollUtil.getLast(cards.get("rest")).substring(0, 1), new LinkedHashMap<>(32), null);
    }

    private void print() throws InterruptedException {

        Player eastPlayer = game.getPlayerList().get(0);
        StringBuilder sb = new StringBuilder("[");
        if (!eastPlayer.getFinished()) {
            log.info("east 实际卡牌：{}", eastPlayer.getCards());

            for (Node child : east.getChildren()) {
                sb.append(child.getId()).append(", ");
            }
            if (sb.length() > 2) {
                sb.delete(sb.length() - 2, sb.length());
            }
            log.info("east 拥有卡牌：{}", sb.append("]"));
            int counter = 0;
            while (east.getChildren().size() != eastPlayer.getCards().size()) {
                if (counter < 10) {
                    Thread.sleep(1000);
                    counter++;
                    continue;
                }
                throw new RuntimeException("error east");
            }
        }

        Player southPlayer = game.getPlayerList().get(1);
        sb = new StringBuilder("[");
        if (!southPlayer.getFinished()) {
            log.info("south 实际卡牌：{}", southPlayer.getCards());
            for (Node child : south.getChildren()) {
                sb.append(child.getId()).append(", ");
            }
            if (sb.length() > 2) {
                sb.delete(sb.length() - 2, sb.length());
            }
            log.info("south 拥有卡牌：{}", sb.append("]"));
            int counter = 0;
            while (south.getChildren().size() != southPlayer.getCards().size()) {
                if (counter < 10) {
                    Thread.sleep(1000);
                    counter++;
                    continue;
                }
                throw new RuntimeException("error south");
            }
        }


        Player westPlayer = game.getPlayerList().get(2);
        sb = new StringBuilder("[");
        if (!westPlayer.getFinished()) {
            log.info("west 实际卡牌：{}", westPlayer.getCards());

            for (Node child : west.getChildren()) {
                sb.append(child.getId()).append(", ");
            }
            if (sb.length() > 2) {
                sb.delete(sb.length() - 2, sb.length());
            }
            log.info("west 拥有卡牌：{}", sb.append("]"));
            int counter = 0;
            while (west.getChildren().size() != westPlayer.getCards().size()) {
                if (counter < 10) {
                    Thread.sleep(1000);
                    counter++;
                    continue;
                }
                throw new RuntimeException("error west");
            }
        }


        Player northPlayer = game.getPlayerList().get(3);
        sb = new StringBuilder("[");
        if (!northPlayer.getFinished()) {
            log.info("north 实际卡牌：{}", northPlayer.getCards());

            for (Node child : north.getChildren()) {
                sb.append(child.getId()).append(", ");
            }

            if (sb.length() > 2) {
                sb.delete(sb.length() - 2, sb.length());
            }
            log.info("north 拥有卡牌：{}", sb.append("]"));
            int counter = 0;
            while (north.getChildren().size() != northPlayer.getCards().size()) {
                if (counter < 10) {
                    Thread.sleep(1000);
                    counter++;
                    continue;
                }
                throw new RuntimeException("error north");
            }
        }

        log.info("剩余卡堆:{}", game.getRestCards());

    }

    private void setCardFlow(String name, String card) {
        if (ObjectUtil.equal(name, "north")) {
            ImageView imageView = new ImageView();
            imageView.setId(card);
            imageView.setFitWidth(53);
            imageView.setFitHeight(75);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/vertical.jpg")));
            north.getChildren().add(imageView);
        } else if (ObjectUtil.equal(name, "east")) {
            ImageView imageView = new ImageView();
            imageView.setId(card);
            imageView.setFitWidth(75);
            imageView.setFitHeight(53);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/horizontal.jpg")));
            east.getChildren().add(imageView);
        } else if (ObjectUtil.equal(name, "south")) {

            ImageView imageView = new ImageView();
            imageView.setId(card);
            imageView.setFitWidth(53);
            imageView.setFitHeight(75);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);
            imageView.setImage(new Image(CommonService.getPicUrl("/img/" + card + ".jpg")));
            imageView.setOnMouseClicked(e -> {

                if (imageView.getEffect() == null) {
                    imageView.setEffect(new DropShadow(15, Color.RED));
                    useCards.add(card);
                } else {
                    imageView.setEffect(null);
                    useCards.remove(card);
                }

            });

            south.getChildren().add(imageView);
        } else {
            ImageView imageView = new ImageView();
            imageView.setId(card);
            imageView.setFitWidth(75);
            imageView.setFitHeight(53);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/horizontal.jpg")));
            west.getChildren().add(imageView);
        }

    }

    private void end() {
        if (game.getRestCards().isEmpty()) {
            game.getPlayerList().stream().filter(c -> c.getCards().isEmpty())
                    .forEach(c -> {
                        c.setFinished(true);
                        c.setRole(null);
                    });

            long endPlayerNum = game.getPlayerList().stream().filter(Player::getFinished).count();
            if (endPlayerNum == 3) {
                game.setIsStarted(false);
                thread = null;
                Player player = game.getPlayerList().stream().filter(c -> !c.getFinished()).findFirst().get();
                Platform.runLater(() -> dialog(StrUtil.format("游戏结束,玩家{}败北", player.getName())));
            } else if (endPlayerNum == 4) {
                game.setIsStarted(false);
                thread = null;
                Platform.runLater(() -> dialog("平局"));
            }
        }
    }

    private void dialog(String text) {
        Dialog<Pair<String, String>> dialog = new Dialog<>();
        dialog.initStyle(StageStyle.UTILITY);
        dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);

        DialogPane dialogPane = dialog.getDialogPane();

        Button btnCancel = (Button) dialogPane.lookupButton(ButtonType.CANCEL);
        btnCancel.setPrefWidth(40);
        btnCancel.setPrefHeight(20);
        btnCancel.setText("返回");
        btnCancel.setOnAction(e -> CommonService.jumpButtonEvent(discard, "main"));

        Button applyBtn = (Button) dialogPane.lookupButton(ButtonType.OK);
        applyBtn.setPrefWidth(40);
        applyBtn.setPrefHeight(20);
        applyBtn.setText("重玩");
        applyBtn.setOnAction(e -> {
            stage.getChildren().clear();
            PokerGen.genNewCard();
            showCard(PokerGen.distributeCard());
            new Thread(() -> {
                try {
                    startGame();
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }).start();
        });

        Label label = new Label(text);
        label.setPrefWidth(150);
        label.setPrefHeight(100);

        dialog.getDialogPane().setContent(label);
        dialog.showAndWait();
    }

}
